package com.msb.sentinelConsumer.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.msb.common.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/****************************************************
 *
 * @author lbf
 * @date 2025/6/26 15:20
 ****************************************************/
@RestController
public class DemoController {

    //服务提供者URL
    @Value("${service-url.nacos-user-service}")
    private String SERVICE_URL;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 使用 @SentinelResource 指定限流的资源
     *
     * todo 注意：
     *     Sentinel 只能处理Sentinel 自身流控相关的异常，Java程序自身的异常是不能够处理的；
     *     但可以通过 @SentinelResource 的属性 “fallback” 来处理程序自身抛出的异常。
     *     如果Sentinel仅仅用来处理程序的异常，则不需要配置流控规则
     *
     * @param id
     * @return
     */
    @SentinelResource(value = "fallback",fallback = "fallbackHandler")
    @GetMapping("/consumer/fallback/{id}")
    public JsonResult<String> fallback(@PathVariable Long id) {

        //模拟异常
        if(id > 3){
            throw new RuntimeException("没有对应的数据~~~");
        }
        //通过Ribbon发起远程访问，访问9003/9004
        JsonResult<String> result = restTemplate.getForObject(SERVICE_URL + "/info/" + id, JsonResult.class);
        return result;
    }

    /**
     * 测试 fallback 与 blockHandler 同时存在时执行顺序的情况
     * 若 fallback 与 blockHandler 同时存在时，当资源 consumer 没有被限流熔断时，执行的是fallback，
     * 当 资源 consumer 被限流熔断时，执行的是 blockHandler
     *
     * @param id
     * @return
     */
    @SentinelResource(value = "consumer",fallback = "fallbackHandler",blockHandler = "blockHandler")
    @GetMapping("/consumer/{id}")
    public JsonResult<String> consumer(@PathVariable Long id) {

        //模拟异常
        if(id > 3){
            throw new RuntimeException("没有对应的数据~~~");
        }
        //通过Ribbon发起远程访问，访问9003/9004
        JsonResult<String> result = restTemplate.getForObject(SERVICE_URL + "/info/" + id, JsonResult.class);
        return result;
    }

    /**
     *  exceptionsToIgnore 属性用于排除指定异常，不计入异常次数；
     *  exceptionsToIgnore 标记的异常也不会执行 fallback，会原样抛出
     *
     * @param id
     * @return
     */
    @SentinelResource(value = "consumer",fallback = "fallbackHandler",blockHandler = "blockHandler",exceptionsToIgnore = {NullPointerException.class})
    @GetMapping("/consumer2/{id}")
    public JsonResult<String> ignore(@PathVariable Long id) {

        //模拟异常
        if(id > 3){
            throw new NullPointerException("没有对应的数据~~~");
        }
        //通过Ribbon发起远程访问，访问9003/9004
        JsonResult<String> result = restTemplate.getForObject(SERVICE_URL + "/info/" + id, JsonResult.class);
        return result;
    }

    /**
     * 该方法包含 @SentinelResource 所标注方法的所有参数，且返回值类型与 @SentinelResource 标注方法的一致，
     * 且是public修饰
     *
     * @param id
     * @param e
     * @return
     */
    public JsonResult fallbackHandler(Long id,Throwable e){

        JsonResult<String> result = new JsonResult<String>();
        result.setCode(500);
        result.setData("没有对应的数据~~~");
        return result;
    }

    /**
     * sentinel 异常
     *
     * @param id
     * @param block
     * @return
     */
    public JsonResult blockHandler(Long id, BlockException block){

        JsonResult<String> result = new JsonResult<String>();
        result.setCode(500);
        result.setData("被限流了~~~");
        return result;
    }



}
